#include "Common.h"
#include "HttpHeader.h"

namespace fx {

    HttpHeader::HttpHeader() 
    {
    }
    HttpHeader::~HttpHeader() 
    {
    }
    HttpHeaderPtr HttpHeader::Create() 
    {
        return HttpHeaderPtr(new HttpHeader());
    }
    HttpHeaderPtr HttpHeader::Create(const std::string& str_buf) 
    {
        HttpHeaderPtr header = HttpHeader::Create();
        if (header->Parse(str_buf))
            return header;
        return HttpHeaderPtr();
    }
    HttpHeaderPtr HttpHeader::Create(std::istream& iss)
    {
        HttpHeaderPtr header = HttpHeader::Create();
        if (header->Parse(iss))
            return header;
        return HttpHeaderPtr();
    }

    bool HttpHeader::ParseKeyValue(const std::string& buffer, const std::string& delim, KeyValuePair& kv_pair)
    {
        boost::uint32_t idx = buffer.find(delim);
        if (idx == std::string::npos)
        {
            kv_pair.first = boost::algorithm::trim_copy(buffer);
            kv_pair.second = "";
        }
        else
        {
            std::string key = boost::algorithm::trim_copy(buffer.substr(0, idx));
            std::string value = boost::algorithm::trim_copy(buffer.substr(idx + delim.length()));
            // result
            kv_pair.first = key;
            kv_pair.second = value;
        }
        return !kv_pair.first.empty();
    }

    bool HttpHeader::Parse(const std::string& str_buf)
    {
        std::istringstream iss(str_buf);
        return Parse(iss);
    }

    bool HttpHeader::Parse(std::istream& iss)
    {
        std::string line;
        if (!getline(iss, line)) {
            return false;
        }

        boost::algorithm::trim(line);
        FirstLine(line);
        if (!ParseFirstLine())
            return false;

        while (getline(iss, line)) {
            if (line.length() == 0)
                return false;
            if (line[0] == '\r')
                break;
            // parse
            KeyValuePair kv;
            if (!ParseKeyValue(line, ":", kv))
                return false;
            // check
            AddHeader(kv.first, kv.second);
        }
        return true;
    }

    std::string HttpHeader::ToString() const
    {
        std::ostringstream oss;
        oss << FirstLine() << "\r\n";
        oss << HeadersBuffer() << "\r\n";
        return oss.str();
    }

    boost::uint32_t HttpHeader::CountHeader(const std::string& key) const
    {
        return headers_.count(key);
    }
    boost::uint32_t HttpHeader::CountHeader(const std::string& key, const std::string& value) const
    {
        boost::uint32_t count = 0;
        MultiMapRange range = headers_.equal_range(key);
        MultiMap::const_iterator it;
        for (it = range.first; it != range.second; ++it) {
            if (value == it->second)
                ++count;
        }
        return count;
    }

    std::string HttpHeader::GetHeader(const std::string& key) const
    {
        MultiMapRange range = headers_.equal_range(key);
        if (range.first == range.second)
            return "";
        return range.first->second;
    }

    std::vector<std::string> HttpHeader::GetHeaders(const std::string& key) const
    {
        std::vector<std::string> results;
        MultiMapRange range = headers_.equal_range(key);
        MultiMap::const_iterator it;
        for (it = range.first; it != range.second; ++it) {
            results.push_back(it->second);
        }
        return results;
    }

    void HttpHeader::AddHeader(const std::string& key, const std::string& value)
    {
        if (CountHeader(key, value) == 0) {
            headers_.insert(make_pair(key, value));
            headers_buffer_.clear();
        }
    }

    void HttpHeader::SetHeader(const std::string& key, const std::string& value)
    {
        headers_.erase(key);
        headers_.insert(make_pair(key, value));
        headers_buffer_.clear();
    }

    boost::uint32_t HttpHeader::RemoveHeaders(const std::string& key)
    {
        boost::uint32_t count = CountHeader(key);
        headers_.erase(key);
        headers_buffer_.clear();
        return count;
    }

    boost::uint32_t HttpHeader::RemoveHeader(const std::string& key, const std::string& value)
    {
        boost::uint32_t count = 0;
        MultiMapRange range = headers_.equal_range(key);
        MultiMap::const_iterator it;
        for (it = range.first; it != range.second; ) {
            if (it->second == value) {
                ++count;
                headers_.erase(it++);
            }
            else {
                ++it;
            }
        }
        if (count > 0) {
            headers_buffer_.clear();
        }
        return count;
    }

    const std::string& HttpHeader::FirstLine() const
    {
        //UpdateFirstLine();
        return first_line_;
    }

    void HttpHeader::FirstLine(const std::string& line)
    {
        first_line_ = line;
    }

    std::string HttpHeader::HeadersBuffer() const
    {
        if (headers_.size() == 0)
            return "";
        if (headers_buffer_.empty())
        {
            std::ostringstream oss;
            MultiMap::const_iterator it;
            for (it = headers_.begin(); it != headers_.end(); ++it) {
                oss << it->first << ": " << it->second << "\r\n";
            }
            headers_buffer_ = oss.str();
        }
        return headers_buffer_;
    }

    bool HttpHeader::ParseFirstLine()
    {
        // nothing
        return true;
    }

    void HttpHeader::UpdateFirstLine()
    {
        // nothing
    }

}